package com.lu.core.aop;

import cn.hutool.extra.servlet.ServletUtil;
import com.lu.core.annotations.SystemLog;
import com.lu.core.support.LogHelper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @program RCS
 * @description:
 * @author: zhanglu
 * @create: 2021-03-09 16:05:00
 */
@Component
@Aspect
@Slf4j
public class SystemLogAop {

    @Pointcut("@annotation(com.lu.core.annotations.SystemLog)")
    public void log() {
    }

    /**
     * 环绕
     * @param proceedingJoinPoint
     * @throws Throwable
     */
    @Around("log()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        //方法上下文
        Signature sig = proceedingJoinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) sig;
        Object target = proceedingJoinPoint.getTarget();
        Method currentMethod = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
        //获取响应参数
        Object result = null;
        //获取调用者ip
        String ip = null;
        //获取调用包名、方法名
        String packageClass = null;
        Map<String, Object> inParams = null;
        //获取注解数据
        SystemLog annotation = currentMethod.getAnnotation(SystemLog.class);
        try {
            //获取调用包名、方法名
            packageClass = proceedingJoinPoint.getSignature().getDeclaringTypeName() + "." + proceedingJoinPoint.getSignature().getName();
            //获取参数名称
            String[] parameterNames = methodSignature.getParameterNames();
            //获取参数值
            Object[] args = proceedingJoinPoint.getArgs();

            //请求参数
            inParams = new HashMap<>();
            for (int i = 0; i < parameterNames.length; i++) {
                if(i >= args.length){
                    break;
                }
                Object value = args[i];
                String name = parameterNames[i];
                if (!(value instanceof HttpServletRequest) && !(value instanceof HttpServletResponse)) {
                    if(value instanceof MultipartFile){
                        inParams.put(name, ((MultipartFile) value).getOriginalFilename());
                    } else {
                        inParams.put(name, value);
                    }
                }
            }

            //HttpServletRequest上下文
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if(attributes != null){
                HttpServletRequest request = attributes.getRequest();
                //获取请求ip
                ip = ServletUtil.getClientIP(request);
            }
            LogHelper.remove();
            //执行方法
            result = proceedingJoinPoint.proceed();

            //记录日志
            LogHelper.build(ip, annotation, packageClass, inParams, result);
        } catch (Exception e) {
            //记录日志
            LogHelper.build(ip, annotation, packageClass, inParams, result, e);
            throw e;
        } finally{
            LogHelper.handler();
        }
        return result;
    }

//    /**
//     * 获取切面注解描述
//     *
//     * @param joinPoint
//     * @return
//     * @throws Exception
//     */
//    public String getAspectLogDescription(JoinPoint joinPoint) throws Exception {
//        String targetName = joinPoint.getTarget().getClass().getName();
//        String methodName = joinPoint.getSignature().getName();
//        Object[] arguments = joinPoint.getArgs();
//        Class targetClass = Class.forName(targetName);
//        Method[] methods = targetClass.getMethods();
//        StringBuilder description = new StringBuilder("");
//        for (Method method : methods) {
//            if (method.getName().equals(methodName)) {
//                Class[] clazzs = method.getParameterTypes();
//                if (clazzs.length == arguments.length) {
//                    description.append(method.getAnnotation(LuBootLog.class).descript());
//                    break;
//                }
//            }
//        }
//        return description.toString();
//    }


}
